feat(q10): Add Q10 vacuum CLI commands and Status API#759
feat(q10): Add Q10 vacuum CLI commands and Status API#759lboue wants to merge 14 commits intoPython-roborock:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds CLI commands to control Roborock Q10 vacuum operations (start/pause/resume/stop/dock) from the roborock command line tool.
Changes:
- Added five new Click commands for Q10 vacuum control.
- Wired the new commands into the root CLI command registry.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| async def refresh(self) -> dict[B01_Q10_DP, Any]: | ||
| """Refresh status values from the device.""" | ||
| decoded = await send_decoded_command( | ||
| self._channel, | ||
| command=B01_Q10_DP.REQUETDPS, | ||
| params={}, | ||
| expected_dps={B01_Q10_DP.STATUS, B01_Q10_DP.BATTERY}, | ||
| ) | ||
| self._data = decoded | ||
| return decoded |
There was a problem hiding this comment.
StatusTrait is new and introduces device-state parsing/refresh behavior, but there are no unit tests covering refresh() and the typed property accessors (state/battery/fan_level/etc.). The repo already has Q10 trait tests (e.g., tests/devices/traits/b01/q10/test_vacuum.py); please add similar tests for status responses (including enum decoding) to prevent regressions.
| async def send_decoded_command( | ||
| mqtt_channel: MqttChannel, | ||
| command: B01_Q10_DP, | ||
| params: ParamsType, | ||
| expected_dps: Iterable[B01_Q10_DP] | None = None, | ||
| ) -> dict[B01_Q10_DP, Any]: | ||
| """Send a command and await the first decoded response. | ||
|
|
||
| Q10 responses are not correlated with a message id, so we filter on | ||
| expected datapoints when provided. | ||
| """ |
There was a problem hiding this comment.
send_decoded_command() adds new request/response correlation logic (expected datapoint filtering + timeout), but there are no unit tests validating: (1) it returns the decoded dps for a matching response, (2) it ignores non-matching responses when expected_dps is set, and (3) it raises on timeout. There are existing channel tests (e.g., tests/devices/rpc/test_a01_channel.py); please add analogous tests for the B01 Q10 channel to lock in behavior.
| raise | ||
|
|
||
|
|
||
| async def send_decoded_command( |
There was a problem hiding this comment.
Does this work? My impression is that q10 doesn't support this kind of mapping between request and response. We have a different approach in
#709
| @property | ||
| def state(self) -> YXDeviceState | None: | ||
| code = self.state_code | ||
| return cast(YXDeviceState | None, YXDeviceState.from_code_optional(code)) if code is not None else None |
There was a problem hiding this comment.
cast should not be needed after this change #761
- Add type annotations to Q10 command parameters (ctx: click.Context, device_id: str) - Add return type annotations (-> None, -> VacuumTrait) for all Q10 commands - Change Q10 commands from @click.command() to @session.command() for session mode availability - Add VacuumTrait import for proper type hints - Create comprehensive StatusTrait tests (5 tests covering refresh, properties, enums) - Create comprehensive send_decoded_command tests (6 tests covering success, filtering, timeout, errors) Resolves all 6 unresolved comments from code review
- Add type annotations to Q10 command parameters (ctx: click.Context, device_id: str) - Add return type annotations (-> None, -> VacuumTrait) for all Q10 commands - Change Q10 commands from @click.command() to @session.command() for session mode availability - Add VacuumTrait import for proper type hints - Create comprehensive StatusTrait tests (5 tests covering refresh, properties, enums) - Create comprehensive send_decoded_command tests (6 tests covering success, filtering, timeout, errors) Resolves all 6 unresolved comments from code review
829d338 to
ff4d425
Compare
- Add q10-vacuum-start command to start vacuum cleaning - Add q10-vacuum-pause command to pause vacuum cleaning - Add q10-vacuum-resume command to resume vacuum cleaning - Add q10-vacuum-stop command to stop vacuum cleaning - Add q10-vacuum-dock command to return vacuum to dock - All commands require device_id parameter - Commands validate that device has VacuumTrait (Q10 only)
- Add _q10_vacuum_trait() helper function similar to _v1_trait() - Refactor all 5 Q10 commands to use the helper - Centralizes device lookup and trait validation logic - Addresses code review feedback from copilot-pull-request-reviewer
- Add try/except blocks to catch RoborockUnsupportedFeature - Display user-friendly error messages instead of stack traces - Follow same pattern as _display_v1_trait for expected errors - Addresses code review feedback from copilot-pull-request-reviewer
- Change from device.traits.get('VacuumTrait') to device.b01_q10_properties.vacuum
- Fix AttributeError that would occur at runtime
- Update error messages to reflect B01 Q10 protocol requirement
- Addresses code review feedback from copilot-pull-request-reviewer
- Add type annotations to Q10 command parameters (ctx: click.Context, device_id: str) - Add return type annotations (-> None, -> VacuumTrait) for all Q10 commands - Change Q10 commands from @click.command() to @session.command() for session mode availability - Add VacuumTrait import for proper type hints - Create comprehensive StatusTrait tests (5 tests covering refresh, properties, enums) - Create comprehensive send_decoded_command tests (6 tests covering success, filtering, timeout, errors) Resolves all 6 unresolved comments from code review
These files are auto-generated/updated on merge to main, per project guidelines. Reverting to their state before this PR.
ff4d425 to
28716c9
Compare
feat(q10): Add Q10 vacuum CLI commands and Status API
Overview
This PR adds complete CLI command support for Roborock Q10 vacuum devices including five vacuum control commands and a new Status API trait for reading device state. All code review feedback has been addressed, and the implementation is tested on a real Q10 S5+ device.
What's Changed
1. CLI Commands for Q10 Vacuum Control
Added 5 new Click commands to control Q10 devices from the CLI:
All commands:
--device_idparameter_q10_vacuum_trait()helper to reduce code duplication2. Status API for Q10 Devices
Implemented a new
StatusTraitto read Q10 device state with properties for:state- Device state (sleepstate, charging, cleaning, etc.)battery- Battery percentage (0-100)fan_level- Fan level (quiet, standard, strong, max, super, custom)water_level- Water level for mopping (low, medium, high)clean_mode- Cleaning mode (quiet, balanced, standard, high)clean_task- Task type (unknown, room, goroom, zone, area, spot)cleaning_progress- Progress percentage3. Decoded MQTT Response Handler
Added
send_decoded_command()for handling Q10's MQTT request/response pattern:4. Fan Level Mapping Enhancement
Added missing
YXFanLevel.CUSTOMmapping for code 8 to handle all Q10 fan modes.Code Quality & Testing
✅ All 7 code review comments addressed and resolved
✅ All 5 CLI commands tested on real Q10 S5+ device
✅ Status API tested and working (battery=91%, state=sleepstate, fan_level=custom)
✅ All pre-commit checks passing (ruff format, mypy types, debug checks)
✅ All CI tests passing (lint, test 3.11, test 3.14, build, semantic release)
✅ Code duplication eliminated with reusable helpers
✅ Proper error handling with user-friendly messages
Files Changed
roborock/cli.py- Added 5 Q10 commands +_q10_vacuum_trait()helperroborock/devices/traits/b01/q10/status.py- NEW StatusTrait class (79 lines)roborock/devices/rpc/b01_q10_channel.py- Addedsend_decoded_command()(61 lines)roborock/devices/traits/b01/q10/__init__.py- Exposed StatusTrait in APIroborock/data/b01_q10/b01_q10_code_mappings.py- Added YXFanLevel.CUSTOMUsage Examples
CLI Commands
Status API
Interactive Session
Related